package com.way.note;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.way.note.data.NoteDataManager;
import com.way.note.data.NoteItem;
import com.way.note.utils.IntentUtils;

public class NoteEditor extends BaseActivity {
	private static final int MAX_CONTENT_LEN = 1000;// char len
	public static final String TAG = "NoteEditor";
	public static final String OPEN_TYPE = "open_type";
	public static final String ID = "id";
	public static final String NOTE_FOLDER_ID = "folder_id";

	public static final int TYPE_NEW_NOTE = 0;
	public static final int TYPE_EDIT_NOTE = 1;

	public static final int DIALOG_DELETE = 0;
	public static final int Dialog_CANCLE = 1;
	public static final int DIALOG_EDIT_TITLE = 2;

	public static final int TITLE_MAX_LEN = 15;

	private static final int MENU_DELETE = Menu.FIRST;
	private static final int MENU_SAVE = Menu.FIRST + 2;
	private static final int MENU_CANCEL = Menu.FIRST + 3;
	private static final int MENU_SHARE = Menu.FIRST + 4;
	private static final int MENU_EDIT_TITLE = Menu.FIRST + 5;

	private Intent mIntent;
	private int mOpenType;

	private TextView mDateTimeTextView;
	private EditText mNowContent;
	private TextView mNoteTitleView;
	private TextView mRemainNumTextView;// used to display characters left
	private String mTemporaryContent;

	private int mId;
	private String mOldContent;
	private boolean needSave = true;
	Date date;
	java.text.DateFormat dateFormat;

	int num = 0;
	NoteDataManager mDataManager = null;
	private NoteItem mNoteItem = null;
	private int mParentFolderID = -1;
	private String mNoteTitle = "";

	private static final boolean DEBUG = true;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mIntent = getIntent();
		if (DEBUG) {
			Log.v(TAG, "OnCreate intent-->" + getIntent() + "  data-->"
					+ (mIntent == null ? "null" : mIntent.getExtras()));
		}
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.note_editor);
		initData();
		initViews();
	}

	private void initData() {
		Intent intent = getIntent();
		mOpenType = intent.getIntExtra(OPEN_TYPE, -1);
		int noteID = intent.getIntExtra(ID, -1);
		mParentFolderID = intent.getIntExtra(NOTE_FOLDER_ID, -1);

		switch (mOpenType) {
		case TYPE_EDIT_NOTE:
			mNoteItem = getDataManager(this).getNoteItem(noteID);
			if (null == mNoteItem) {
				if (DEBUG) {
					Log.d(TAG, "initData --> noteItem is null. Type: "
							+ mOpenType + "ID: " + noteID + ", folderID"
							+ mParentFolderID);
				}
				return;
			}
			break;

		case TYPE_NEW_NOTE:
			mOldContent = "";
			mNoteItem = new NoteItem(mParentFolderID);
			break;

		default:
			break;
		}
		mNoteTitle = mNoteItem.getTitle();
		num = mNoteItem.getContent().length();
		mOldContent = mNoteItem.content;
	}

	private void initViews() {
		mRemainNumTextView = (TextView) findViewById(R.id.remain_num);
		mDateTimeTextView = (TextView) findViewById(R.id.tv_note_date_time);
		mNowContent = (EditText) findViewById(R.id.et_content);
		mNoteTitleView = (TextView) findViewById(R.id.note_title);
		mNowContent.setAutoLinkMask(0x01 | 0x02 | 0x04);// web, email, phone
		mNowContent.setVisibility(View.VISIBLE);
		mNowContent.setCursorVisible(true);

		mNowContent.setFilters(new InputFilter[] {
				new BaseActivity.ToastLenFilter(MAX_CONTENT_LEN),// limit len
				new InputFilter.LengthFilter(MAX_CONTENT_LEN) });
		mNowContent.addTextChangedListener(textwatch);

		mNoteTitleView.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				editTitle();
			}
		});
	}

	@Override
	protected void onStart() {
		super.onStart();
		Log.v(TAG, "onStart");
	}

	@Override
	protected void onResume() {
		super.onResume();
		Log.v(TAG, "onResume");
		if (mNoteItem != null) {
			updateDisplay();
		}
	}

	private void updateDisplay() {
		mRemainNumTextView.setText(num + "" + "/" + MAX_CONTENT_LEN);
		mDateTimeTextView.setText(mNoteItem.getDate(this) + "   "
				+ mNoteItem.getTime(this));
		Log.d(TAG, "mTemporaryContent=" + mTemporaryContent);
		if (mTemporaryContent != null) {
			mNowContent.setText(mTemporaryContent);
		} else {
			mNowContent.setText(mNoteItem.getContent());
		}
		int selection_end = (mNowContent.getText().toString()).length();// cursor
																		// position
		mNowContent.setSelection(selection_end);
		mNoteTitleView.setText(mNoteTitle);
	}

	@SuppressWarnings("static-access")
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(menu.NONE, MENU_EDIT_TITLE, 1, R.string.edit_title).setIcon(
				R.drawable.ic_menu_edit);
		menu.add(Menu.NONE, MENU_SAVE, 4, R.string.save).setIcon(
				R.drawable.save);
		menu.add(menu.NONE, MENU_SHARE, 5, R.string.share).setIcon(
				android.R.drawable.ic_menu_share);
		menu.add(Menu.NONE, MENU_DELETE, 6, R.string.delete).setIcon(
				R.drawable.delete);
		menu.add(Menu.NONE, MENU_CANCEL, 7, R.string.Cancel).setIcon(
				R.drawable.delete);
		return super.onCreateOptionsMenu(menu);
	}

	public boolean onPrepareOptionsMenu(Menu menu) {
		switch (mOpenType) {
		case TYPE_NEW_NOTE:
			menu.findItem(MENU_CANCEL).setVisible(true);
			menu.findItem(MENU_DELETE).setVisible(false);
			break;
		case TYPE_EDIT_NOTE:
			menu.findItem(MENU_CANCEL).setVisible(false);
			menu.findItem(MENU_DELETE).setVisible(true);
			break;
		default:
			break;
		}
		return super.onPrepareOptionsMenu(menu);
	};

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (DEBUG) {
			Log.v(TAG,
					"onOptionsItemSelected: item.getItemId-->"
							+ item.getItemId());
		}
		Bundle bundle = new Bundle();
		switch (item.getItemId()) {
		case MENU_DELETE:
			bundle.putInt("tag", DIALOG_DELETE);
			showDialog(bundle);
			break;
		case MENU_CANCEL:
			bundle.putInt("tag", Dialog_CANCLE);
			showDialog(bundle);
			break;
		case MENU_SAVE:
			saveNote();
			finish();
			break;
		case MENU_SHARE:
			if (null != mNoteItem
					&& isNoteNotEmptyAndToast(R.string.input_content)) {
				saveNote();
				IntentUtils.sendSharedIntent(this, mNoteItem);
			} else {
				Log.d(TAG, "noteItem is null");
			}
			break;
		case MENU_EDIT_TITLE:
			editTitle();
			break;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void editTitle() {
		Bundle bundle = new Bundle();
		bundle.putInt("tag", DIALOG_EDIT_TITLE);
		bundle.putString("now_title", getNowTitle2Edit());
		showDialog(bundle);
	}

	private String getNowTitle2Edit() {// edit title
		if (mNoteTitle == null) {
			mNoteTitle = "";
		}
		return mNoteTitle;
	}

	private boolean isNoteNotEmptyAndToast(int toastResID) {
		if (isNoteEmpty()) {
			Toast.makeText(NoteEditor.this, toastResID, Toast.LENGTH_SHORT)
					.show();
			return false;
		} else {
			return true;
		}
	}

	// tile and content are empty will return true
	private boolean isNoteEmpty() {
		return mNoteTitleView.getText().toString().trim().isEmpty()
				&& mNowContent.getText().toString().trim().isEmpty();
	}

	TextWatcher textwatch = new TextWatcher() {
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
		}

		public void onTextChanged(CharSequence s, int start, int before,
				int count) {
		}

		public void afterTextChanged(Editable s) {
			int number = s.length();
			mRemainNumTextView.setText("" + number + "/" + MAX_CONTENT_LEN);
		}
	};

	@Override
	protected void onNewIntent(Intent intent) {
		Log.i(TAG, "onNewIntent() intent-->" + intent + " extars-->"
				+ (intent == null ? "null" : intent.getExtras().toString()));
		setIntent(intent);
	}

	@Override
	protected void onPause() {
		mTemporaryContent = mNowContent.getText().toString();
		super.onPause();
		Log.i(TAG, "onPause() needSave-->" + needSave);
	}

	@Override
	protected void onStop() {
		super.onStop();
		Log.i(TAG, "OnStop");
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		outState.putString("now_content", mNowContent.getText().toString());
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		mTemporaryContent = savedInstanceState.getString("now_content");
	}

	@Override
	public void finish() {
		if (needSave) {
			saveNote();
		}
		Log.i(TAG, "OnStop");
		super.finish();
	}

	private void saveNote() {
		if (!isNoteNotEmptyAndToast(R.string.save_failed)) {
			return;
		}
		String content = mNowContent.getText().toString();
		if (DEBUG) {
			Log.v(TAG, "openType =" + mOpenType + " content-->" + content);
		}
		switch (mOpenType) {
		case TYPE_NEW_NOTE:
			insertNote(content);
			break;
		case TYPE_EDIT_NOTE:
			updateNote(content);
			break;
		default:
			break;
		}
	}

	private boolean isTitleValid() {
		switch (mOpenType) {
		case TYPE_NEW_NOTE:
			if (mNoteTitle != null && !mNoteTitle.equals("")) {
				return true;
			}
			break;
		case TYPE_EDIT_NOTE:
			if (mNoteTitle != null && !mNoteTitle.equals(mNoteItem.getTitle())) {
				return true;
			}
			break;
		}
		return false;
	}

	private void insertNote(String content) {
		if (content.length() > 0 || isTitleValid()) {// content is not empty or
														// title need update
			if (null == mNoteItem) {
				Log.d(TAG, "insertNote --> noteItem is null");
				return;
			}
			mNoteItem.title = mNoteTitle;
			mNoteItem.content = content;
			getDataManager(this).insertItem(mNoteItem);
			mOldContent = content;
			mOpenType = TYPE_EDIT_NOTE;
			Toast.makeText(NoteEditor.this, R.string.save_success,
					Toast.LENGTH_SHORT).show();
		}
	}

	private void updateNote(String content) {
		if (DEBUG) {
			Log.v(TAG, "_id =" + mId + " ; content =" + content
					+ " ; mNoteTitle =" + mNoteTitle);
		}
		mNoteTitle = (mNoteTitle == null ? "" : mNoteTitle);
		content = (content == null ? "" : content);
		if (mNoteTitle.length() == 0 && content.length() == 0) {
			Toast.makeText(NoteEditor.this, R.string.save_failed,
					Toast.LENGTH_SHORT).show();
			return;
		} else if ((!content.equals(mOldContent)) || isTitleValid()) {// at
																		// least
																		// change
																		// the
																		// title
																		// or
																		// content
			if (null == mNoteItem) {
				Log.d(TAG, "updateNote --> noteItem is null");
				return;
			}
			mNoteItem.title = mNoteTitle;
			mNoteItem.content = content;
			mOldContent = content;
			mNoteItem.date = new Date().getTime();
			getDataManager(this).updateItem(mNoteItem);
			Toast.makeText(NoteEditor.this, R.string.save_success,
					Toast.LENGTH_SHORT).show();
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		Log.v(TAG, "onDestory");
	}

	/**
	 * A custom EditText that draws lines between each line of text that is
	 * displayed.
	 */
	public static class LinedEditText extends EditText {
		private Rect mRect;
		private Paint mPaint;
		private static final String TAG = "NoteEditText";
		private static final String SCHEME_TEL = "tel:";
		private static final String SCHEME_HTTP = "http:";
		private static final String SCHEME_EMAIL = "mailto:";

		private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
		static {
			sSchemaActionResMap.put(SCHEME_TEL, R.string.tel);
			sSchemaActionResMap.put(SCHEME_HTTP, R.string.web);
			sSchemaActionResMap.put(SCHEME_EMAIL, R.string.email);
		}

		// we need this constructor for LayoutInflater
		public LinedEditText(Context context, AttributeSet attrs) {
			super(context, attrs);
			setWillNotDraw(false);
			setLinkTextColor(0xFF0069FF);
			setLinksClickable(false);
			mRect = new Rect();
			mPaint = new Paint();
			PathEffect effects = new DashPathEffect(new float[] { 1, 2, 4, 8 },
					1);
			mPaint.setPathEffect(effects);
			mPaint.setStyle(Paint.Style.STROKE);
			mPaint.setStrokeWidth(1);
			mPaint.setColor(Color.parseColor("#dbab29"));
		}

		@Override
		protected void onDraw(Canvas canvas) {
			int count = getLineCount();
			Rect r = mRect;
			Paint paint = mPaint;

			for (int i = 0; i < count; i++) {
				int baseline = getLineBounds(i, r);
				Log.d(TAG, "LinedEditText onDraw baseline :" + baseline);
				canvas.drawLine(0, baseline + 5, r.right, baseline + 5, paint);
			}
			super.onDraw(canvas);
		}

		@Override
		protected void onCreateContextMenu(ContextMenu menu) {
			int selStart = getSelectionStart();
			int selEnd = getSelectionEnd();

			int min = Math.min(selStart, selEnd);
			int max = Math.max(selStart, selEnd);

			final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max,
					URLSpan.class);
			if (urls.length == 1) {
				int defaultResId = 0;
				for (String schema : sSchemaActionResMap.keySet()) {
					if (urls[0].getURL().indexOf(schema) >= 0) {
						defaultResId = sSchemaActionResMap.get(schema);
						break;
					}
				}

				if (defaultResId == 0) {
					defaultResId = R.string.note_link_other;
				}

				menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
						new OnMenuItemClickListener() {
							public boolean onMenuItemClick(MenuItem item) {
								// goto a new intent
								urls[0].onClick(LinedEditText.this);
								return true;
							}
						});
			}
			super.onCreateContextMenu(menu);
		}
	}

	@Override
	public void onBackPressed() {
		try {
			super.onBackPressed();
		} catch (IllegalStateException e) {
			finish();
		}
	}

	public static class AlertDialogFragment extends DialogFragment {

		@Override
		public Dialog onCreateDialog(Bundle savedInstanceState) {
			final Bundle bundle = getArguments();
			if (bundle == null) {
				return null;
			}
			final int fragmentTag = bundle.getInt("tag");
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
			switch (fragmentTag) {
			case DIALOG_DELETE:
				builder.setTitle(R.string.delete_note);
				builder.setNegativeButton(R.string.Cancel, null);
				builder.setPositiveButton(R.string.Ok,
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								((NoteEditor) getActivity())
										.doPositiveClick(bundle);
							}
						});
				break;
			case Dialog_CANCLE:
				builder.setTitle(R.string.cancel_confirm);
				builder.setNegativeButton(R.string.Cancel, null);
				builder.setPositiveButton(R.string.Ok,
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								((NoteEditor) getActivity())
										.doPositiveClick(bundle);
							}
						});
				break;
			case DIALOG_EDIT_TITLE:
				View customTitleView = LayoutInflater.from(getActivity())
						.inflate(R.layout.dialog_title_layout, null);
				TextView titleText = (TextView) customTitleView
						.findViewById(R.id.note_editor_title);
				titleText.setText(R.string.edit_title);
				builder.setCustomTitle(customTitleView);
				final TextView mEditorCharCountView = (TextView) customTitleView
						.findViewById(R.id.char_count);
				View layout = LayoutInflater.from(getActivity()).inflate(
						R.layout.dialog_layout_new_folder, null);
				builder.setView(layout);
				final EditText titleView = (EditText) layout
						.findViewById(R.id.et_dialog_new_folder);
				titleView.addTextChangedListener(new TextWatcher() {
					Toast toast;

					@Override
					public void onTextChanged(CharSequence s, int start,
							int before, int count) {

					}

					@Override
					public void beforeTextChanged(CharSequence s, int start,
							int count, int after) {

					}

					@Override
					public void afterTextChanged(Editable s) {
						int length = s.toString().length();
						mEditorCharCountView.setText(length + "/"
								+ TITLE_MAX_LEN);
						if (length > TITLE_MAX_LEN) {
							String toastMessage = getActivity().getString(
									R.string.tilte_input_more, TITLE_MAX_LEN);
							if (toast == null) {
								toast = Toast.makeText(getActivity(),
										toastMessage, Toast.LENGTH_SHORT);
							}
							toast.show();
							s.delete(TITLE_MAX_LEN, length);
						}
					}
				});
				titleView.setText(bundle.getString("now_title"));// set title
																	// text
				titleView.setSelection(titleView.getText().toString().length());
				Button renameBtnCancel = (Button) layout
						.findViewById(R.id.button_cancel);
				Button renameBtnOk = (Button) layout
						.findViewById(R.id.button_ok);
				renameBtnCancel.setOnClickListener(new View.OnClickListener() {

					@Override
					public void onClick(View v) {
						((NoteEditor) getActivity())
								.doNegativeClick(fragmentTag);
					}
				});
				renameBtnOk.setOnClickListener(new View.OnClickListener() {

					@Override
					public void onClick(View v) {
						String title = titleView.getText().toString().trim();
						bundle.putString("new_title", title);
						((NoteEditor) getActivity()).doPositiveClick(bundle);
					}
				});
				break;

			default:
				break;
			}
			return builder.create();
		}
	}

	void showDialog(Bundle bundle) {
		AlertDialogFragment dialogFragment = new AlertDialogFragment();
		dialogFragment.setArguments(bundle);
		dialogFragment.show(getFragmentManager(), "" + bundle.getInt("tag"));
	}

	public void doPositiveClick(Bundle bundle) {
		switch (bundle.getInt("tag")) {
		case DIALOG_DELETE:
			if (null == mNoteItem) {
				Log.d(TAG, "onCreateDialog --> noteItem is null");
				return;
			}
			needSave = false;
			getDataManager(NoteEditor.this).deleteNoteItem(mNoteItem);
			Toast.makeText(getApplicationContext(), R.string.delete_success,
					Toast.LENGTH_SHORT).show();
			NoteEditor.this.finish();
			break;
		case Dialog_CANCLE:
			needSave = false;
			NoteEditor.this.finish();
			break;
		case DIALOG_EDIT_TITLE:
			mNoteTitle = bundle.getString("new_title");
			mNoteTitleView.setText(mNoteTitle);
			AlertDialogFragment dialogFragment = (AlertDialogFragment) getFragmentManager()
					.findFragmentByTag("" + bundle.getInt("tag"));
			if (dialogFragment != null) {
				dialogFragment.dismiss();
			}
			break;
		default:
			break;
		}

	}

	public void doNegativeClick(int fragmentTag) {
		switch (fragmentTag) {
		case DIALOG_EDIT_TITLE:
			AlertDialogFragment dialogFragment = (AlertDialogFragment) getFragmentManager()
					.findFragmentByTag("" + fragmentTag);
			if (dialogFragment != null) {
				dialogFragment.dismiss();
			}
			break;
		}

	}

}
